﻿#region Creditos

/* Autor: Edilberto Sánchez Forero	*/
/* Email: esanchezfo@gmail.com		*/
/* Licencia: LGPL, Software Libre	*/
/* País: Colombia, Bogotá			*/

#endregion

#region Librerias

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

#endregion


namespace ESF.General.Text
{
	public class ShortGuid
	{
		#region Static
 
		/// <summary>
		/// A read-only instance of the ShortGuid class whose value
		/// is guaranteed to be all zeroes.
		/// </summary>
		public static readonly ShortGuid Empty = new ShortGuid(Guid.Empty);
	 
		#endregion
	 
		#region Fields
	 
		Guid _guid;
		string _value;
	 
		#endregion
	 
		#region Contructors
	 
		/// <summary>
		/// Creates a ShortGuid from a base64 encoded string
		/// </summary>
		/// <param name="value">The encoded guid as a
		/// base64 string</param>
		public ShortGuid(string value)
		{
		  _value = value;
		  _guid = Decode(value);
		}
	 
		/// <summary>
		/// Creates a ShortGuid from a Guid
		/// </summary>
		/// <param name="guid">The Guid to encode</param>
		public ShortGuid(Guid guid)
		{
		  _value = Encode(guid);
		  _guid = guid;
		}
	 
		#endregion
	 
		#region Properties
	 
		/// <summary>
		/// Gets/sets the underlying Guid
		/// </summary>
		public Guid Guid
		{
		  get { return _guid; }
		  set
		  {
			if (value != _guid)
			{
			  _guid = value;
			  _value = Encode(value);
			}
		  }
		}
	 
		/// <summary>
		/// Gets/sets the underlying base64 encoded string
		/// </summary>
		public string Value
		{
		  get { return _value; }
		  set
		  {
			if (value != _value)
			{
			  _value = value;
			  _guid = Decode(value);
			}
		  }
		}
	 
		#endregion
	 
		#region ToString
	 
		/// <summary>
		/// Returns the base64 encoded guid as a string
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
		  return _value;
		}
	 
		#endregion
	 
		#region Equals
	 
		/// <summary>
		/// Returns a value indicating whether this instance and a
		/// specified Object represent the same type and value.
		/// </summary>
		/// <param name="obj">The object to compare</param>
		/// <returns></returns>
		public override bool Equals(object obj)
		{
		  if (obj is ShortGuid)
			return _guid.Equals(((ShortGuid)obj)._guid);
		  if (obj is Guid)
			return _guid.Equals((Guid)obj);
		  if (obj is string)
			return _guid.Equals(((ShortGuid)obj)._guid);
		  return false;
		}
	 
		#endregion
	 
		#region GetHashCode
	 
		/// <summary>
		/// Returns the HashCode for underlying Guid.
		/// </summary>
		/// <returns></returns>
		public override int GetHashCode()
		{
		  return _guid.GetHashCode();
		}
	 
		#endregion
	 
		#region NewGuid
	 
		/// <summary>
		/// Initialises a new instance of the ShortGuid class
		/// </summary>
		/// <returns></returns>
		public static ShortGuid NewGuid()
		{
		  return new ShortGuid(Guid.NewGuid());
		}
	 
		#endregion
	 
		#region Encode
	 
		/// <summary>
		/// Creates a new instance of a Guid using the string value,
		/// then returns the base64 encoded version of the Guid.
		/// </summary>
		/// <param name="value">An actual Guid string (i.e. not a ShortGuid)</param>
		/// <returns></returns>
		public static string Encode(string value)
		{
		  Guid guid = new Guid(value);
		  return Encode(guid);
		}
	 
		/// <summary>
		/// Encodes the given Guid as a base64 string that is 22
		/// characters long.
		/// </summary>
		/// <param name="guid">The Guid to encode</param>
		/// <returns></returns>
		public static string Encode(Guid guid)
		{
		  string encoded = Convert.ToBase64String(guid.ToByteArray());
		  encoded = encoded
			.Replace("/", "_")
			.Replace("+", "-");
		  return encoded.Substring(0, 22);
		}
	 
		#endregion
	 
		#region Decode
	 
		/// <summary>
		/// Decodes the given base64 string
		/// </summary>
		/// <param name="value">The base64 encoded string of a Guid</param>
		/// <returns>A new Guid</returns>
		public static Guid Decode(string value)
		{
		  value = value
			.Replace("_", "/")
			.Replace("-", "+");
		  byte[] buffer = Convert.FromBase64String(value + "==");
		  return new Guid(buffer);
		}
	 
		#endregion
	 
		#region Operators
	 
		/// <summary>
		/// Determines if both ShortGuids have the same underlying
		/// Guid value.
		/// </summary>
		/// <param name="x"></param>
		/// <param name="y"></param>
		/// <returns></returns>
		public static bool operator ==(ShortGuid x, ShortGuid y)
		{
		  if ((object)x == null) return (object)y == null;
		  return x._guid == y._guid;
		}
	 
		/// <summary>
		/// Determines if both ShortGuids do not have the
		/// same underlying Guid value.
		/// </summary>
		/// <param name="x"></param>
		/// <param name="y"></param>
		/// <returns></returns>
		public static bool operator !=(ShortGuid x, ShortGuid y)
		{
		  return !(x == y);
		}
	 
		/// <summary>
		/// Implicitly converts the ShortGuid to it's string equivilent
		/// </summary>
		/// <param name="shortGuid"></param>
		/// <returns></returns>
		public static implicit operator string(ShortGuid shortGuid)
		{
		  return shortGuid._value;
		}
	 
		/// <summary>
		/// Implicitly converts the ShortGuid to it's Guid equivilent
		/// </summary>
		/// <param name="shortGuid"></param>
		/// <returns></returns>
		public static implicit operator Guid(ShortGuid shortGuid)
		{
		  return shortGuid._guid;
		}
	 
		/// <summary>
		/// Implicitly converts the string to a ShortGuid
		/// </summary>
		/// <param name="shortGuid"></param>
		/// <returns></returns>
		public static implicit operator ShortGuid(string shortGuid)
		{
		  return new ShortGuid(shortGuid);
		}
	 
		/// <summary>
		/// Implicitly converts the Guid to a ShortGuid
		/// </summary>
		/// <param name="guid"></param>
		/// <returns></returns>
		public static implicit operator ShortGuid(Guid guid)
		{
		  return new ShortGuid(guid);
		}
	 
		#endregion
	}
}
